package pl.drypisy;

import java.awt.image.BufferedImage;

/**
 * Created with IntelliJ IDEA.
 * User: adam
 * Date: 08.01.13
 * Time: 19:03
 * Abstract image processor class. Contains a method for bilinear interpolation. The process method should be a two-step
 * process. The first step is to calculate necessary matrixes/values/anything needed for transformation. The second step
 * should be to apply the transformations to image, preferably line by line (not for each pixel - it's very slow).
 */
abstract class ImageProcess {
    protected boolean doInterpolation = true;
    abstract public BufferedImage process(BufferedImage img);
    abstract protected void getOriginalCoordinates(int x, int y, double out[]);
    protected int srcWidth, srcHeight;

    /**
     * Does a bilinear interpolation on ARGB values.
     *
     * @param xw x-weight, values from range [0.0; 1.0]
     * @param yw x-weight, values from range [0.0; 1.0]
     * @param nw North-West point RGB values.
     * @param ne North-East point RGB values.
     * @param sw South-West point RGB values.
     * @param se South-East point RGB values.
     * @return Interpolated RGB values.
     */
    protected int bilinearInterpolation(double xw, double yw, int nw, int ne, int sw, int se) {
        double m0, m1;
        int a0 = (nw >> 24) & 0xff;
        int r0 = (nw >> 16) & 0xff;
        int g0 = (nw >> 8) & 0xff;
        int b0 = nw & 0xff;
        int a1 = (ne >> 24) & 0xff;
        int r1 = (ne >> 16) & 0xff;
        int g1 = (ne >> 8) & 0xff;
        int b1 = ne & 0xff;
        int a2 = (sw >> 24) & 0xff;
        int r2 = (sw >> 16) & 0xff;
        int g2 = (sw >> 8) & 0xff;
        int b2 = sw & 0xff;
        int a3 = (se >> 24) & 0xff;
        int r3 = (se >> 16) & 0xff;
        int g3 = (se >> 8) & 0xff;
        int b3 = se & 0xff;

        double cx = 1.0f - xw;
        double cy = 1.0f - yw;

        m0 = cx * a0 + xw * a1;
        m1 = cx * a2 + xw * a3;
        int a = (int) (cy * m0 + yw * m1);

        m0 = cx * r0 + xw * r1;
        m1 = cx * r2 + xw * r3;
        int r = (int) (cy * m0 + yw * m1);

        m0 = cx * g0 + xw * g1;
        m1 = cx * g2 + xw * g3;
        int g = (int) (cy * m0 + yw * m1);

        m0 = cx * b0 + xw * b1;
        m1 = cx * b2 + xw * b3;
        int b = (int) (cy * m0 + yw * m1);
        return (a << 24) | (r << 16) | (g << 8) | b;
    }

    protected int getPixel( int[] pixels, int x, int y, int width, int height ) {
        if (x < 0 || x >= width || y < 0 || y >= height) {
            return 0;
        }
        return pixels[ y*width+x ];
    }

    protected void setInterpolate(boolean i)
    {
        doInterpolation = i;
    }
    
    BufferedImage clippImage(BufferedImage img){
        int clipN = 0;
        int clipS = 0;
        int clipW = 0;
        int clipE = 0;
        srcWidth = img.getWidth();
        srcHeight = img.getHeight();
        int srcRGB[] = img.getRGB(0, 0, srcWidth, srcHeight, null, 0, srcWidth);
        int i,j;
        for (i = 0; i < srcWidth*srcHeight; ++i){
            if(srcRGB[i] != 0){
                clipN = i/srcWidth;
                break;
            }
        }
        for (i = srcWidth*srcHeight - 1; i > 0; --i){
            if(srcRGB[i] != 0){
                clipS = srcHeight - i/srcWidth -1;
                break;
            }
        }
        boolean stop = false;
        for(j = 0 ; j < srcWidth ; ++j ){
           for(i = 0 ; i < srcHeight ; ++i ){
               int srcPos = i*srcWidth + j;
               if(srcRGB[srcPos] != 0){
                clipW = j;
                stop = true;
                break;
                }
           }
           if(stop){
               break;
           }
        }
        stop = false;
        for(j = srcWidth-1 ; j > 0 ; --j ){
           for(i = srcHeight -1 ; i > 0 ; --i ){
               int srcPos = i*srcWidth + j;
               if(srcRGB[srcPos] != 0){
                clipE = srcWidth - j - 1;
                stop = true;
                break;
                }
           }
           if(stop){
               break;
           }
        }
        int width = srcWidth - clipE - clipW;
        int height = srcHeight - clipN - clipS;
        int destRGB[] = img.getRGB(clipW, clipN, width, height, null, 0, width);
        BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        dest.setRGB(0,0,width,height,destRGB,0,width);
        return dest;
    }
    
}